﻿using Microsoft.EntityFrameworkCore;
using Abp.Zero.EntityFrameworkCore;
using FwProject.Authorization.Roles;
using FwProject.Authorization.Users;
using FwProject.MultiTenancy;
using FwProject.Core.Car;
using FwProject.Core.FactoryInfo;
using FwProject.Core.Restaurant;
using FwProject.Core.TypeNumber;
using FwProject.Core.Distribution;
using FwProject.Core.SettlementInfoModel;
using FwProject.Core.AppVersion;
using FwProject.Car;
using FwProject.Restaurant;
using FwProject.Distribution;
using FwProject.PrePaymentInfo;
using FwProject.ManagerConfig;
using System.Linq.Expressions;
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using System.Reflection;
using FwProject.Core.DataFilterFactoryinfo;
using Abp.Domain.Uow;
using Microsoft.AspNetCore.Http;
using System.Linq;

namespace FwProject.EntityFrameworkCore
{
    public class FwProjectDbContext : AbpZeroDbContext<Tenant, Role, User, FwProjectDbContext>
    {
        
        /* Define a DbSet for each entity of the application */
        #region 工厂对应的工厂信息，工厂对应汽车信息，工厂对应的餐厅信息
        public DbSet<FactoryNameInfo> FactoryInfoDetail { get; set; }
        public DbSet<CarInfo> CarInfo { get; set; }
        public DbSet<RestaurantInfo> RestaurantInfo { get; set; }
        #endregion
        #region 餐厅对应的绑定老板信息，餐厅对应的绑定产品信号信息
        public DbSet<RestaurantUserInfo> RestaurantUserInfo { get; set; }
        public DbSet<RestaurantTypenNumberInfo> RestaurantTypenNumberInfo { get; set; }
        #endregion
        #region 餐厅对应产品型号
        public DbSet<TypeNumberInfo> TypeNumberInfo { get; set; }

        #endregion
        #region 装车数据
        public DbSet<LoadCar> LoadCar { get; set; }
        public DbSet<LoadingCarInfo> LoadingCarInfo { get; set; }
        public DbSet<LoadCarRecovery> LoadCarRecovery { get; set; }
        #endregion
        #region 餐厅配送情况
        public DbSet<DistributionInfo> DistributionInfo { get; set; }
        public DbSet<DistributionInfoDetails> DistributionInfoDetails { get; set; }
        #endregion
        #region 餐厅收款情况
        public DbSet<SettlementInfo> SettlementInfo { get; set; }
        #endregion
        #region App版本管理
        public DbSet<AppVersionManger> AppVersionManger { get; set; }
        #endregion
        #region 汽车配送地图位置
        public DbSet<CarMap> CarMap { get; set; }
        #endregion
        #region 押金
        public DbSet<DepositInfo> DepositInfo { get; set; }
        #endregion
        #region 配送线路
        /// <summary>
        /// 配送线路
        /// </summary>
        public DbSet<DistributionLine> DistributionLine { get; set; }
        /// <summary>
        /// 司机绑定线路
        /// </summary>
        public DbSet<DriverLine> DriverLine { get; set; }
        #endregion
        #region 餐厅店存盘点
        /// <summary>
        /// 店存盘点
        /// </summary>
        public DbSet<StockCheckInfo> StockCheckInfo { get; set; }
        #endregion
        #region 餐厅预付款
        public DbSet<PrePaymentInfoModel> PrePaymentInfoModel { get; set; }

        #endregion
        #region 工厂账户
        public DbSet<SettlementAccount> SettlementAccounts { get; set; }
        #endregion
        #region  缴款凭证生成
        public DbSet<PaymentInfoModel> PaymentInfoModel { get; set; }

        public DbSet<ReceiptInfoModel> ReceiptInfoModel { get; set; }
        #endregion

        public DbSet<ConfigInfo> ConfigInfo { get; set; }

        public DbSet<DistributionHistory> DistributionHistory { get; set; }

        public DbSet<PaymentInfoByReceipt> PaymentInfoByReceipt { get; set; }

        public DbSet<ReceiptInfoBySettlementModel> ReceiptInfoBySettlementModel { get; set; }

        public DbSet<DriverTypeNumber> DriverTypeNumber { get; set; }


        public FwProjectDbContext(DbContextOptions<FwProjectDbContext> options)
            : base(options)
        {
           
        }

     

        private static MethodInfo ConfigureGlobalFiltersMethodInfo = typeof(FwProjectDbContext).GetMethod(nameof(DbConfigureGlobalFilters), BindingFlags.Instance | BindingFlags.NonPublic);

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            foreach (var entityType in modelBuilder.Model.GetEntityTypes())
            {
                ConfigureGlobalFiltersMethodInfo
                     .MakeGenericMethod(entityType.ClrType)
                     .Invoke(this, new object[] { modelBuilder, entityType });

            }


           
        }
        protected void DbConfigureGlobalFilters<TEntity>(ModelBuilder modelBuilder, IMutableEntityType entityType)
             where TEntity : class
        {      
            if (entityType.BaseType == null && DbShouldFilterEntity<TEntity>(entityType))
            {
                var filterExpression = DbCreateFilterExpression<TEntity>();
                if (filterExpression != null)
                {
                    modelBuilder.Entity<TEntity>().HasQueryFilter(filterExpression);
                }
            }
            
        }
        protected virtual bool DbShouldFilterEntity<TEntity>(IMutableEntityType entityType) where TEntity : class
        {
            if (typeof(IHasFactroyinfo).IsAssignableFrom(typeof(TEntity)))
            {
                return true;
            }

            return false;
        }
        
        protected virtual Expression<Func<TEntity, bool>> DbCreateFilterExpression<TEntity>()
         where TEntity : class
        {
            Expression<Func<TEntity, bool>> expression = null;

            if (typeof(IHasFactroyinfo).IsAssignableFrom(typeof(TEntity)))
            {
                /* This condition should normally be defined as below:
                 * !IsSoftDeleteFilterEnabled || !((ISoftDelete) e).IsDeleted
                 * But this causes a problem with EF Core (see https://github.com/aspnet/EntityFrameworkCore/issues/9502)
                 * So, we made a workaround to make it working. It works same as above.
                 */
                string factoryinfoId = string.Empty;
                try
                {
                    foreach (var item in CurrentUnitOfWorkProvider.Current.Filters)
                    {
                        if (item.FilterName == FwConsts.FactroyInfoFilter && item.FilterParameters.Count > 0)
                            factoryinfoId = item.FilterParameters[FwConsts.FactoryinfoId] == null ? string.Empty : item.FilterParameters[FwConsts.FactoryinfoId].ToString();
                    }
                    if (!string.IsNullOrEmpty(factoryinfoId))
                    {
                        Expression<Func<TEntity, bool>> softFactroyinfoFilter = e => ((IHasFactroyinfo)e).FactoryinfoId.Value == Guid.Parse(factoryinfoId);
                        expression = expression == null ? softFactroyinfoFilter : CombineExpressions(expression, softFactroyinfoFilter);
                    }

                }
                catch (Exception exe)
                {
                    factoryinfoId = string.Empty;
                }
                finally {

                }
              
            }


            return expression;
        }



}
}
